import { audioErrorHandler } from './AudioErrorHandler'

/**
 * 音频管理器类，负责管理游戏中的所有音频播放
 * 使用Web Audio API提供高性能的音频处理能力
 * @class
 */
export class AudioManager {
  private audioContext: AudioContext | null = null;
  private soundEffects: Map<string, AudioBuffer> = new Map();
  private backgroundMusic: AudioBuffer | null = null;
  private masterVolume: number = 1.0;
  private musicVolume: number = 0.7;
  private sfxVolume: number = 0.8;
  private currentMusicSource: AudioBufferSourceNode | null = null;
  private musicGainNode: GainNode | null = null;
  private sfxGainNode: GainNode | null = null;
  private isInitialized: boolean = false;

  /**
   * 初始化音频管理器
   * 创建AudioContext和必要的音频节点
   * @returns Promise<void>
   * @throws 当浏览器不支持Web Audio API时抛出错误
   */
  async initialize(): Promise<void> {
    try {
      // 创建AudioContext
      this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
      
      // 创建音量控制节点
      this.musicGainNode = this.audioContext.createGain();
      this.sfxGainNode = this.audioContext.createGain();
      
      // 连接到音频输出
      this.musicGainNode.connect(this.audioContext.destination);
      this.sfxGainNode.connect(this.audioContext.destination);
      
      // 设置初始音量
      this.updateVolumes();
      
      this.isInitialized = true;
      console.log('AudioManager 初始化成功');
    } catch (error) {
      console.error('AudioManager 初始化失败:', error);
      // 使用错误处理器处理AudioContext错误
      audioErrorHandler.handleAudioContextError(error as Error, this.audioContext || undefined);
      throw new Error('浏览器不支持Web Audio API');
    }
  }

  /**
   * 加载音频文件
   * @param name - 音频文件的标识名称
   * @param url - 音频文件的URL路径
   * @returns Promise<void>
   * @throws 当音频文件加载失败时抛出错误
   * @example
   * await audioManager.loadSound('jump', '/sounds/jump.mp3');
   */
  async loadSound(name: string, url: string): Promise<void> {
    if (!this.audioContext) {
      throw new Error('AudioManager 未初始化');
    }

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP错误: ${response.status}`);
      }
      
      const arrayBuffer = await response.arrayBuffer();
      const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
      
      this.soundEffects.set(name, audioBuffer);
      console.log(`音效 "${name}" 加载成功`);
    } catch (error) {
      console.error(`加载音效 "${name}" 失败:`, error);
      // 使用错误处理器处理音频加载错误
      const handled = audioErrorHandler.handleSoundLoadError(error as Error, name, url);
      if (!handled) {
        throw new Error(`无法加载音效文件: ${url}`);
      }
    }
  }

  /**
   * 加载背景音乐
   * @param url - 背景音乐文件的URL路径
   * @returns Promise<void>
   * @throws 当背景音乐加载失败时抛出错误
   * @example
   * await audioManager.loadBackgroundMusic('/music/background.mp3');
   */
  async loadBackgroundMusic(url: string): Promise<void> {
    if (!this.audioContext) {
      throw new Error('AudioManager 未初始化');
    }

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP错误: ${response.status}`);
      }
      
      const arrayBuffer = await response.arrayBuffer();
      this.backgroundMusic = await this.audioContext.decodeAudioData(arrayBuffer);
      
      console.log('背景音乐加载成功');
    } catch (error) {
      console.error('加载背景音乐失败:', error);
      throw new Error(`无法加载背景音乐文件: ${url}`);
    }
  }

  /**
   * 播放音效
   * @param name - 要播放的音效名称
   * @param volume - 音量大小 (0-1)，可选参数
   * @returns boolean - 是否成功播放
   * @example
   * audioManager.playSound('jump', 0.8);
   */
  playSound(name: string, volume: number = 1.0): boolean {
    if (!this.isInitialized || !this.audioContext || !this.sfxGainNode) {
      console.warn('AudioManager 未初始化，无法播放音效');
      return false;
    }

    const audioBuffer = this.soundEffects.get(name);
    if (!audioBuffer) {
      console.warn(`音效 "${name}" 未找到`);
      return false;
    }

    try {
      // 创建音频源节点
      const source = this.audioContext.createBufferSource();
      source.buffer = audioBuffer;
      
      // 创建音量节点
      const gainNode = this.audioContext.createGain();
      gainNode.gain.value = Math.max(0, Math.min(1, volume));
      
      // 连接音频节点
      source.connect(gainNode);
      gainNode.connect(this.sfxGainNode);
      
      // 播放音效
      source.start();
      
      return true;
    } catch (error) {
      console.error(`播放音效 "${name}" 失败:`, error);
      // 使用错误处理器处理播放错误
      audioErrorHandler.handlePlaybackError(error as Error, name);
      return false;
    }
  }

  /**
   * 播放背景音乐
   * @param loop - 是否循环播放，默认为true
   * @returns boolean - 是否成功播放
   * @example
   * audioManager.playMusic(true);
   */
  playMusic(loop: boolean = true): boolean {
    if (!this.isInitialized || !this.audioContext || !this.musicGainNode) {
      console.warn('AudioManager 未初始化，无法播放背景音乐');
      return false;
    }

    if (!this.backgroundMusic) {
      console.warn('背景音乐未加载');
      return false;
    }

    // 停止当前播放的音乐
    this.stopMusic();

    try {
      // 创建新的音频源节点
      this.currentMusicSource = this.audioContext.createBufferSource();
      this.currentMusicSource.buffer = this.backgroundMusic;
      this.currentMusicSource.loop = loop;
      
      // 连接到音量控制节点
      this.currentMusicSource.connect(this.musicGainNode);
      
      // 开始播放
      this.currentMusicSource.start();
      
      console.log('背景音乐开始播放');
      return true;
    } catch (error) {
      console.error('播放背景音乐失败:', error);
      return false;
    }
  }

  /**
   * 停止背景音乐播放
   * @example
   * audioManager.stopMusic();
   */
  stopMusic(): void {
    if (this.currentMusicSource) {
      try {
        this.currentMusicSource.stop();
      } catch {
        // 忽略已经停止的音频源的错误
      }
      this.currentMusicSource = null;
      console.log('背景音乐已停止');
    }
  }

  /**
   * 设置主音量
   * @param volume - 音量大小 (0-1)
   * @example
   * audioManager.setMasterVolume(0.8);
   */
  setMasterVolume(volume: number): void {
    this.masterVolume = Math.max(0, Math.min(1, volume));
    this.updateVolumes();
  }

  /**
   * 设置背景音乐音量
   * @param volume - 音量大小 (0-1)
   * @example
   * audioManager.setMusicVolume(0.6);
   */
  setMusicVolume(volume: number): void {
    this.musicVolume = Math.max(0, Math.min(1, volume));
    this.updateVolumes();
  }

  /**
   * 设置音效音量
   * @param volume - 音量大小 (0-1)
   * @example
   * audioManager.setSfxVolume(0.9);
   */
  setSfxVolume(volume: number): void {
    this.sfxVolume = Math.max(0, Math.min(1, volume));
    this.updateVolumes();
  }

  /**
   * 获取当前主音量
   * @returns 当前主音量值 (0-1)
   */
  getMasterVolume(): number {
    return this.masterVolume;
  }

  /**
   * 获取当前背景音乐音量
   * @returns 当前背景音乐音量值 (0-1)
   */
  getMusicVolume(): number {
    return this.musicVolume;
  }

  /**
   * 获取当前音效音量
   * @returns 当前音效音量值 (0-1)
   */
  getSfxVolume(): number {
    return this.sfxVolume;
  }

  /**
   * 检查音频管理器是否已初始化
   * @returns 是否已初始化
   */
  isReady(): boolean {
    return this.isInitialized;
  }

  /**
   * 获取已加载的音效列表
   * @returns 音效名称数组
   */
  getLoadedSounds(): string[] {
    return Array.from(this.soundEffects.keys());
  }

  /**
   * 检查背景音乐是否已加载
   * @returns 是否已加载背景音乐
   */
  hasBackgroundMusic(): boolean {
    return this.backgroundMusic !== null;
  }

  /**
   * 检查背景音乐是否正在播放
   * @returns 是否正在播放背景音乐
   */
  isMusicPlaying(): boolean {
    return this.currentMusicSource !== null;
  }

  /**
   * 更新所有音量节点的音量值
   * @private
   */
  private updateVolumes(): void {
    if (this.musicGainNode) {
      this.musicGainNode.gain.value = this.masterVolume * this.musicVolume;
    }
    if (this.sfxGainNode) {
      this.sfxGainNode.gain.value = this.masterVolume * this.sfxVolume;
    }
  }

  /**
   * 销毁音频管理器，释放所有资源
   * @example
   * audioManager.destroy();
   */
  destroy(): void {
    this.stopMusic();
    
    if (this.audioContext) {
      this.audioContext.close();
      this.audioContext = null;
    }
    
    this.soundEffects.clear();
    this.backgroundMusic = null;
    this.musicGainNode = null;
    this.sfxGainNode = null;
    this.isInitialized = false;
    
    console.log('AudioManager 已销毁');
  }
}

/**
 * 音频管理器单例实例
 * 全局唯一的音频管理器实例，确保整个应用中音频状态的一致性
 * @example
 * import { audioManager } from '@/game/AudioManager';
 * await audioManager.initialize();
 */
export const audioManager = new AudioManager();